package misc;

import java.lang.reflect.Method;
import java.util.List;

import nl.preflag.basewars.R;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Paint.Style;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;
import com.google.android.maps.Projection;

/**
 * @author Patrick van Gils, 0787862, INF3M
 * Itemized balloon overlay
 */

public abstract class BalloonItemizedOverlay<Item> extends ItemizedOverlay<OverlayItem> {

	private MapView mapView;
	private BalloonOverlayView balloonView;
	private View clickRegion;
	int viewOffset, player_id, base_id, baseType, baseHealth;
	final MapController mc;
	private GeoPoint geopoint2;
	private static final int CIRCLERADIUS = 60;
	private Boolean showRadius;
	private Bitmap bmp;
	
	/**
	 * Itemized balloon overlay constructor
	 * 
	 * @param defaultMarker
	 * @param mapView
	 * @param point
	 * @param radius
	 * @param pid
	 * @param bid
	 * @param bType
	 * @param bHealth
	 */
	public BalloonItemizedOverlay(Drawable defaultMarker, MapView mapView, GeoPoint point, Boolean radius, int pid, int bid, int bType, int bHealth) {
		super(defaultMarker);
		this.mapView = mapView;
		viewOffset = 0;
		geopoint2 = point;
		mc = mapView.getController();
		showRadius = radius;
		player_id = pid;
		base_id = bid; 
		baseType = bType;
		baseHealth = bHealth;
	}
	
	/**
	 * Balloon bottom offset
	 * 
	 * @param pixels
	 */
	public void setBalloonBottomOffset(int pixels) {
		viewOffset = pixels;
	}
	
	/**
	 * Balloon tap
	 * 
	 * @param index
	 * @return
	 */
	protected boolean onBalloonTap(int index) {
		return false;
	}

	@Override
    public void draw(Canvas canvas, MapView mapView, boolean shadow) {
        
		Projection projection = mapView.getProjection();
        Point point = new Point();
        projection.toPixels(geopoint2, point);
		
        // Check what type of base it is (1=me, 2=friend, 3=enemy)
        switch (baseType) {
	        case 1:
	        	switch (baseHealth) {
	        	case 100:
	        		bmp = BitmapFactory.decodeResource(mapView.getResources(), R.drawable.base_me);
	        		break;
	        	default:
	        		bmp = BitmapFactory.decodeResource(mapView.getResources(), R.drawable.base_me_damaged);
	        		break;
	        	}
	        	
	        	// Draw circle if radius is true
	        	if (showRadius == true) {
	            	Paint circlePaint = new Paint();
	                circlePaint.setStrokeWidth(1);
	                circlePaint.setAntiAlias(true);

	                // Draw the outer circle
	                circlePaint.setARGB(255, 100, 156, 210);
	                circlePaint.setStyle(Style.STROKE);
	                canvas.drawCircle(point.x, point.y, CIRCLERADIUS + 1,
	                        circlePaint);

	                //Fill the circle
	                circlePaint.setARGB(100, 100, 156, 210);
	                circlePaint.setStyle(Style.FILL_AND_STROKE);
	                canvas.drawCircle(point.x, point.y, CIRCLERADIUS, circlePaint);
	        	}
	        	break;
	        case 2:
	        	switch (baseHealth) {
		        	case 100:
		        		bmp = BitmapFactory.decodeResource(mapView.getResources(), R.drawable.base_friend);
		        		break;
		        	default:
		        		bmp = BitmapFactory.decodeResource(mapView.getResources(), R.drawable.base_friend_damaged);
		        		break;
	        	}
	        	break;
	        case 3:
	        	switch (baseHealth) {
	        		case 100:
		        		bmp = BitmapFactory.decodeResource(mapView.getResources(), R.drawable.base_enemy);
		        		break;
		        	default:
		        		bmp = BitmapFactory.decodeResource(mapView.getResources(), R.drawable.base_enemy_damaged);
	        	}
	        	break;
        }
        

        Paint pushpinPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        canvas.drawBitmap(bmp, point.x -30, point.y -30, pushpinPaint);
    }
	
	@Override
	protected final boolean onTap(int index) {
		
		boolean isRecycled;
		final int thisIndex;
		GeoPoint point;
		
		thisIndex = index;
		point = createItem(index).getPoint();
		
		/*
		 *  Create Balloon overlay view
		 *  Invoke this method with the following params: base_id, player_id and baseType.
		 *  baseType makes the difference between me, friend and enemies.
		 */
		if (balloonView == null) {
			balloonView = new BalloonOverlayView(mapView.getContext(), viewOffset, base_id, player_id, baseType, baseHealth);
			switch (baseType) {
	        case 1:
	        		clickRegion = (View) balloonView.findViewById(R.id.balloon_inner_layout);
	        	break;
	        case 2:
        		clickRegion = (View) balloonView.findViewById(R.id.balloon_inner_layout);
        		break;
	        case 3:
        			clickRegion = (View) balloonView.findViewById(R.id.balloon_inner_layout_enemy);
        	break;	
			}
			
			isRecycled = false;
		} else {
			isRecycled = true;
		}
	
		balloonView.setVisibility(View.GONE);
		
		List<Overlay> mapOverlays = mapView.getOverlays();
		if (mapOverlays.size() > 1) {
			hideOtherBalloons(mapOverlays);
		}
		
		balloonView.setData(createItem(index));
		
		MapView.LayoutParams params = new MapView.LayoutParams(
				LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, point,
				MapView.LayoutParams.BOTTOM_CENTER);
		params.mode = MapView.LayoutParams.MODE_MAP;
		
		setBalloonTouchListener(thisIndex);
		
		balloonView.setVisibility(View.VISIBLE);

		if (isRecycled) {
			balloonView.setLayoutParams(params);
		} else {
			mapView.addView(balloonView, params);
		}
		
		mc.animateTo(point);
		return true;
	}
	
	/**
	 * Sets the visibility of this overlay's balloon view to GONE. 
	 */
	private void hideBalloon() {
		if (balloonView != null) {
			balloonView.setVisibility(View.GONE);
		}
	}
	
	/**
	 * Hide other balloons
	 * 
	 * @param overlays
	 */
	private void hideOtherBalloons(List<Overlay> overlays) {
		
		for (Overlay overlay : overlays) {
			if (overlay instanceof BalloonItemizedOverlay<?> && overlay != this) {
				((BalloonItemizedOverlay<?>) overlay).hideBalloon();
			}
		}
	}
	
	/**
	 * Set balloon ontouch listener
	 * 
	 * @param thisIndex
	 */
	private void setBalloonTouchListener(final int thisIndex) {
		
		try {
			@SuppressWarnings("unused")
			Method m = this.getClass().getDeclaredMethod("onBalloonTap", int.class);
			
			clickRegion.setOnTouchListener(new OnTouchListener() {
				public boolean onTouch(View v, MotionEvent event) {
					
					View l =  ((View) v.getParent()).findViewById(R.id.balloon_main_layout);
					Drawable d = l.getBackground();
					
					if (event.getAction() == MotionEvent.ACTION_DOWN) {
						int[] states = {android.R.attr.state_pressed};
						if (d.setState(states)) {
							d.invalidateSelf();
						}
						return true;
					} else if (event.getAction() == MotionEvent.ACTION_UP) {
						int newStates[] = {};
						if (d.setState(newStates)) {
							d.invalidateSelf();
						}
						// call overridden method
						onBalloonTap(thisIndex);
						return true;
					} else {
						return false;
					}
					
				}
			});
			
		} catch (SecurityException e) {
			Log.e("BalloonItemizedOverlay", "setBalloonTouchListener reflection SecurityException");
			return;
		} catch (NoSuchMethodException e) {
			// method not overridden - do nothing
			return;
		}
	}
}
